﻿using System;
using System.Collections;
using System.Collections.Generic;
using Gameplay.PVE.Utils;
using UnityEngine;
using UnityEngine.Profiling;
using XLua;

#if UNITY_EDITOR
[UnityEditor.CanEditMultipleObjects]
#endif
public class ModelHitPoint : MonoBehaviour
{
    public List<Transform> hitPoints;
    public List<Vector2> hitPointsMissRange;
    public Transform hudPoint;
    public float hudHeight;
    public List<Transform> gunPoints;
    
    public List<Transform> bulletCastPoints;
    public List<Transform> skillEffectPoints;
    public Transform flyTextPoint;
    public Transform flyTextCriticalPoint;
    public List<Transform> buffEffectPoints;
    public Transform anchorPoint;
    public Transform rotationBase;

    public Transform shield;
    
    public List<Transform> bulletPoints;
    [Tooltip("技能序号，从1开始，普攻->主动->被动")]
    public List<int> bulletPointsType;

    public List<Vector3> bulletPointSpeed;
    [Tooltip("技能序号，从1开始，普攻->主动->被动")]
    public List<int> bulletPointsSpeedType;
    
    [BlackList] public Transform templateBulletPoint;

    public List<GameObject> weapons;
    
    public float hitDuration = 0.5f;
    
    public void BindGameObjectOnPoint(int pointType,int pointIndex,int bindType,GameObject gameObject)
    {
        bindDataList.Add(new BindObjectData
        {
            pointType = pointType,
            pointIndex = pointIndex,
            bindType = bindType,
            transform = gameObject.transform,
        });
    }

    public struct BindObjectData
    {
        public Transform transform;
        public int pointType;
        public int pointIndex;
        public int bindType;
        public Vector3 position;
        public Vector3 angle;
        public float scale;
    }

    private List<BindObjectData> bindDataList = new List<BindObjectData>(10);

    private const int POINT_TYPE_HIT = 1;
    private const int POINT_TYPE_GUN = 2;
    private const int POINT_TYPE_BULLET_CASE = 3;
    private const int POINT_TYPE_SKILL = 4;

    private const int BIND_TYPE_NOT_SET_PARENT = 0;
    private const int BIND_TYPE_SET_PARENT = 1;
    private const int BIND_TYPE_GROUND = 10;
    
    private void LateUpdate()
    {
        Profiler.BeginSample("ModelHitPoint.LateUpdate.UpdateBindDataList");
        for (int i = 0; i < bindDataList.Count; i++)
        {
            var data = bindDataList[i];
            var pointType = data.pointType;
            var pointIndex = data.pointIndex;
            var objTrans = data.transform;
            Transform point = null;
            if (pointType == POINT_TYPE_GUN)
            {
                point = GetPoint(gunPoints, pointIndex);
            }
            else if (pointType == POINT_TYPE_HIT)
            {
                point = GetPoint(hitPoints, pointIndex);
            }
            else if (pointType == POINT_TYPE_SKILL)
            {
                point = GetPoint(skillEffectPoints, pointIndex);
            }
            else if (pointType == POINT_TYPE_BULLET_CASE)
            {
                point = GetPoint(bulletCastPoints, pointIndex);
            }

            if (point)
            {
                objTrans.position = point.position;
                objTrans.forward = point.forward;
                var bindType = data.bindType;
                if (bindType == BIND_TYPE_SET_PARENT)
                {
                    objTrans.SetParent(point);
                }
            }
        }
        bindDataList.Clear();
        Profiler.EndSample();
    }

    private Transform GetPoint(List<Transform> list,int index)
    {
        if (list == null || list.Count <= index)
        {
            return null;
        }

        return list[index];
    }

    public void SwitchWeapon(int index,int backupIndex = -1)
    {
        if (weapons != null)
        {
            if (weapons.Count > index)
            {
                for (int i = 0; i < weapons.Count; i++)
                {
                    weapons[i].SetActive(index == i || backupIndex == i);
                }
            }
        }
    }

    private SkinnedMeshRenderer[] skinnedMeshRenderer;
    private MeshRenderer[] meshRenderer;
    private List<Material[]> originMaterialsSMR;
    private List<Material[]> shadowMaterialsSMR;
    
    private List<Material[]> originMaterialsM;
    private List<Material[]> shadowMaterialsM;
    
    [HideInInspector]
    public bool hasInitedShadowData = false;

    private bool hasShadow = false;

    public void InitShadow(Material modelShadow)
    {
        if (!hasInitedShadowData)
        {
            skinnedMeshRenderer = GetComponentsInChildren<SkinnedMeshRenderer>();
            originMaterialsSMR = new List<Material[]>();
            shadowMaterialsSMR = new List<Material[]>();
            for (int i = 0; i < skinnedMeshRenderer.Length; i++)
            {
                var skin = skinnedMeshRenderer[i];
                var mats = skin.sharedMaterials;
                var newMats = new Material[mats.Length + 1];
                for (int k = 0; k < mats.Length; k++)
                {
                    newMats[k] = mats[k];
                }
                newMats[newMats.Length - 1] = modelShadow;
                originMaterialsSMR.Add(mats);
                shadowMaterialsSMR.Add(newMats);
            }

            meshRenderer = GetComponentsInChildren<MeshRenderer>();
            originMaterialsM = new List<Material[]>();
            shadowMaterialsM = new List<Material[]>();
            for (int i = 0; i < meshRenderer.Length; i++)
            {
                var renderer = meshRenderer[i];
                var mats = renderer.sharedMaterials;
                var newMats = new Material[mats.Length + 1];
                for (int k = 0; k < mats.Length; k++)
                {
                    newMats[k] = mats[k];
                }
                newMats[newMats.Length - 1] = modelShadow;
                originMaterialsM.Add(mats);
                shadowMaterialsM.Add(newMats);
            }
            hasInitedShadowData = true;
        }
    }
    
    public void SetShadowVisible(bool visible)
    {
        if (!hasInitedShadowData)
        {
            return;
        }
        if (hasShadow != visible)
        {
            hasShadow = visible;
            for (int i = 0; i < skinnedMeshRenderer.Length; i++)
            {
                skinnedMeshRenderer[i].sharedMaterials = visible ? shadowMaterialsSMR[i] : originMaterialsSMR[i];
            }

            for (int i = 0; i < meshRenderer.Length; i++)
            {
                meshRenderer[i].sharedMaterials = visible ? shadowMaterialsM[i] : originMaterialsM[i];
            }
        }
    }
}
